package com.gitee.wsl.common.chart.render.background.axis.line

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import com.gitee.wsl.common.chart.ChartEnum
import com.gitee.wsl.common.chart.render.background.axis.BaseAxis
import com.gitee.wsl.common.chart.render.background.axis.model.PlotAxisTick
import com.gitee.wsl.android.ui.ext.type.*
import com.gitee.wsl.common.ui.draw.type.VerticalAlign
import com.gitee.wsl.transform.format.Format
import com.gitee.wsl.math.Math
import com.gitee.wsl.jvm.math.add
import com.gitee.wsl.jvm.math.sub
import com.gitee.wsl.mathematics.geometry.shape.Rectangle


/**
 * @ClassName XYAxis
 * @Description XY坐标系类，定义了具体的绘制及格式回调函数的处理
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 *
 */

abstract class BaseLineAxis: BaseAxis() {
    // 数据集
     var dataSet: List<String> = emptyList()

    //标签集
     val lstLabels = mutableListOf<PlotAxisTick>()

    // 用于格式化标签的回调接口
    var labelFormatter: Format<String>? = null

    //标签显示位置，分别在轴的左边，中间，右边
    var tickMarksAlign = Paint.Align.RIGHT

    //标签显示位置，分别在轴的上面，中间，底下
    var tickMarksPosition = VerticalAlign.BOTTOM

    //默认刻度线所占宽度
    open var tickMarksLength = 15f

    //刻度标记与轴的间距
    var tickLabelMargin = 10f

    var isShowAxisLabels = true

    var axisLineStyle = ChartEnum.AxisLineStyle.NONE

    var axisLineStyleWidth = 20f
    var axisLineStyleHeight = 30f

    // 标签按哪种风格显示
    var labelLineFeed = ChartEnum.LabelLineFeed.NORMAL

    //轴分隔值
    var axisSteps = 0.0f

    /**
     * 正负标准值处理，激活后，数据与标准值比较后，依大小向各自方向绘制
     */
    var isAxisStdStatus = false

    /**
     * 设置分类轴数据源
     * @param dataSet 数据源
     */
    fun setDataBuilding(dataSet: List<String>) {
        this.dataSet = dataSet
    }

    /**
     * 设置轴线上三角箭头属性
     * @param width  箭头宽度
     * @param height 箭头高度
     */
     fun setAxisLinxCapWH(width: Float, height: Float) {
        axisLineStyleWidth = width
        axisLineStyleHeight = height
    }

    /**
     * 返回标签显示格式
     *
     * @param value 传入当前值
     * @return 显示格式
     */
    protected  fun getFormatterLabel(text: String): String {
        return labelFormatter?.invoke(text)?:text
    }

    ///////////////////////////////////////////////////////////////
    //绘制轴线

    /**
     * 绘制轴
     * @param canvas 画布
     * @param startX 起始点X坐标
     * @param startY 起始点Y坐标
     * @param stopX      结束点X坐标
     * @param stopY      结束点Y坐标
     */
    fun renderAxis(canvas: Canvas, startX: Float, startY: Float, stopX: Float, stopY: Float) {
        if ( isAxisVisible && isAxisLineVisible ) {
            drawAxisLine(canvas, startX, startY, stopX, stopY)
        }
    }


    fun renderClipAxisLine(canvas: Canvas, plotArea: Rectangle, mDataAxisLocation: ChartEnum.AxisLocation = this.axisLocation) {
        val plotLeft: Float = plotArea.left
        val plotTop: Float = plotArea.top
        val plotRight: Float = plotArea.right
        val plotBottom: Float = plotArea.bottom

        when (mDataAxisLocation) {
            ChartEnum.AxisLocation.LEFT ->
                renderAxis(canvas, plotLeft, plotBottom, plotLeft, plotTop)

            ChartEnum.AxisLocation.RIGHT ->
                renderAxis(canvas, plotRight, plotTop, plotRight, plotBottom)

            ChartEnum.AxisLocation.VERTICAL_CENTER -> {
                val vcX = plotLeft + (plotRight - plotLeft) / 2
                //val hcY = plotTop + (plotBottom - plotTop) / 2
                renderAxis(canvas, vcX, plotTop, vcX, plotBottom)
            }
            ChartEnum.AxisLocation.TOP ->
                renderAxis(canvas, plotLeft, plotTop, plotRight, plotTop)

            ChartEnum.AxisLocation.BOTTOM ->
                renderAxis(canvas, plotLeft, plotBottom, plotRight, plotBottom)

            ChartEnum.AxisLocation.HORIZONTAL_CENTER -> {
                //val vcX = plotLeft + (plotRight - plotLeft) / 2
                val hcY = plotTop + (plotBottom - plotTop) / 2
                renderAxis(canvas, plotLeft, hcY, plotRight, hcY)
            }
        }
    }

    protected  fun drawAxisLine(
        canvas: Canvas,
        startX: Float,
        startY: Float,
        stopX: Float,
        stopY: Float
    ) {
        if (ChartEnum.AxisLineStyle.CAP == axisLineStyle || ChartEnum.AxisLineStyle.FILLCAP == axisLineStyle) {
            val w = axisLineStyleWidth / 2
            var angleTop = 0f
            var axisEnd = axisLineStyleHeight / 2
            val path = Path()
            if (startY.compareTo(stopY) != 0) //竖轴
            {
                angleTop = stopY - axisLineStyleHeight
                val angleLeftX = stopX - w
                val angleRightX = stopX + w
                axisEnd += angleTop
                if (ChartEnum.AxisLineStyle.FILLCAP == axisLineStyle) {
                    path.moveTo(angleLeftX, axisEnd)
                    path.lineTo(stopX, angleTop)
                    path.lineTo(angleRightX, axisEnd)
                    path.close()
                    canvas.drawPath(path, axisPaint)
                    canvas.drawLine(startX, startY, stopX, axisEnd, this.axisPaint)
                } else {
                    canvas.drawLine(startX, startY, stopX, angleTop, this.axisPaint)
                    canvas.drawLine(angleLeftX, axisEnd, stopX, angleTop, this.axisPaint)
                    canvas.drawLine(angleRightX, axisEnd, stopX, angleTop, this.axisPaint)
                }
            } else {
                angleTop = stopX + axisLineStyleHeight
                val angleTopY = stopY - w
                val angleBottom = stopY + w
                axisEnd = angleTop - axisEnd
                if (ChartEnum.AxisLineStyle.FILLCAP == axisLineStyle) {
                    path.moveTo(axisEnd, angleTopY)
                    path.lineTo(angleTop, stopY)
                    path.lineTo(axisEnd, angleBottom)
                    path.close()
                    canvas.drawPath(path, axisPaint)
                    canvas.drawLine(startX, startY, axisEnd, stopY, this.axisPaint)
                } else {
                    canvas.drawLine(startX, startY, angleTop, stopY, this.axisPaint)
                    canvas.drawLine(axisEnd, angleTopY, angleTop, stopY, this.axisPaint)
                    canvas.drawLine(axisEnd, angleBottom, angleTop, stopY, this.axisPaint)
                }
            }
        } else { //none
            canvas.drawLine(startX, startY, stopX, stopY, this.axisPaint)
        }
    }

    abstract fun renderClipAxisClosed(
        canvas: Canvas,
        plotArea: Rectangle,
        axisLocation: ChartEnum.AxisLocation = this.axisLocation
    )


    ////////////////////////////////////////////////////////
    //标签
    /**
     * 竖轴坐标标签，依左，中，右，决定标签横向显示在相对中心点的位置
     * @param centerX 轴上中点X坐标
     * @param centerY 轴上中点X坐标
     * @param text    标签文本
     */
    // odd-even
    fun drawHorizontalTick(
        chatLeft: Float, plotLeft: Float ,
        canvas: Canvas ,
        centerX: Float ,
        centerY: Float ,
        text: String ,
        labelX: Float = centerX,
        labelY: Float = centerY,
        isTickVisible: Boolean = true
    ) {
        if (!isAxisVisible) return
        var marksStartX = centerX
        var markeStopX = centerX
        var labelStartX = labelX
        when (tickMarksAlign) {
            Paint.Align.LEFT -> {
                if (isTickMarksVisible) {
                    marksStartX =  Math.sub(centerX, tickMarksLength)
                    markeStopX = centerX
                }
                if (this.isAxisLabelsVisible)
                    labelStartX = Math.sub(marksStartX, tickLabelMargin)
            }
            Paint.Align.CENTER -> {
                if (isTickMarksVisible) {
                    marksStartX = Math.sub(centerX, (tickMarksLength / 2))
                    markeStopX =  Math.add(centerX, (tickMarksLength / 2))
                }
            }
            Paint.Align.RIGHT -> {
                if (isTickMarksVisible) {
                    marksStartX = centerX
                    markeStopX =  Math.add(centerX, tickMarksLength)
                }
                if (this.isAxisLabelsVisible)
                    labelStartX = Math.add(markeStopX, tickLabelMargin)
            }
            else -> {}
        }

        //横轴刻度线
        if (isTickMarksVisible && isTickVisible) {
            canvas.drawLine(
                marksStartX, centerY,
                Math.add(markeStopX, this.axisPaint.strokeWidth / 2),
                centerY,
                tickMarkPaint
            )
        }

        //标签
        //  当标签文本太长时，可以考虑分成多行显示如果实在太长，则开发用...来自己处理
        if (isAxisLabelsVisible) {
            drawHorizontalTickLabels(
                chatLeft, plotLeft, canvas,
                labelStartX, labelY, markeStopX, text
            )
        }
    }


    /**
     * 横轴坐标标签，决定标签显示在相对中心点的上方，中间还是底部位置
     * @param centerX    轴上中点X坐标
     * @param centerY    轴上中点Y坐标
     * @param text        标签文本
     */
     protected fun drawVerticalTick(
        canvas: Canvas,
        centerX: Float,
        centerY: Float,
        text: String,
        labelX: Float = centerX,
        labelY: Float = centerY,
        isTickVisible: Boolean = true,
        oe: ChartEnum.ODD_EVEN = ChartEnum.ODD_EVEN.NONE
    ) {
        if (!isAxisVisible) return
        var marksStartY = centerY
        var marksStopY = centerY
        var labelsStartY = labelY
        when (tickMarksPosition) {
            VerticalAlign.TOP -> {
                if (isTickMarksVisible) {
                    marksStartY =  Math.sub(centerY, tickMarksLength)
                    marksStopY = centerY
                }
                marksStartY =  Math.sub(centerY, tickMarksLength)
                marksStopY = centerY
            }
            VerticalAlign.MIDDLE -> {
                if (isTickMarksVisible) {
                    marksStartY =  Math.sub(centerY, (tickMarksLength / 2))
                    marksStopY =  Math.add(centerY, (tickMarksLength / 2))
                }
            }
            VerticalAlign.BOTTOM -> {
                if (isTickMarksVisible) {
                    marksStartY = centerY
                    //marksStopY = Math.round(centerY + mTickMarksLength);		
                    marksStopY =  Math.add(centerY, tickMarksLength)
                }
                if (this.isAxisLabelsVisible) {
                    labelsStartY = marksStopY + tickLabelMargin + (tickLabelPaint.lineHeight / 3)
                }
            }
        }
        if (isTickMarksVisible && isTickVisible) {
            val mstartX =  Math.sub(marksStartY, axisPaint.strokeWidth / 2)

            //if( Float.compare(mstartX, xchart.getPlotArea().getLeft()) == -1) ||
            //		Float.compare(mstartX, xchart.getPlotArea().getRight()) == 1 	)
            //{				
            //}else{	
            canvas.drawLine(
                centerX,
                mstartX,  //	marksStartY - this.mPaintAxis.getStrokeWidth() / 2,					
                centerX,
                marksStopY, tickMarkPaint
            )
            //}
        }
        if (isAxisLabelsVisible) {
            val labelHeight = tickLabelPaint.lineHeight
            
            var currY = labelsStartY
            if (labelLineFeed != ChartEnum.LabelLineFeed.NORMAL) {
                when (labelLineFeed) {
                    ChartEnum.LabelLineFeed.ODD_EVEN -> if (oe == ChartEnum.ODD_EVEN.ODD) currY += labelHeight
                    ChartEnum.LabelLineFeed.EVEN_ODD -> if (oe == ChartEnum.ODD_EVEN.EVEN) currY += labelHeight
                    ChartEnum.LabelLineFeed.NORMAL -> {}
                }
            }

            //定制化显示格式			
            canvas.drawRotateText(
                getFormatterLabel(text),
                labelX, currY,  //labelsStartY,
                tickLabelRotateAngle,
                tickLabelPaint
            )
            //Log.e("t2","2angle:"+Float.toString(mTickLabelRotateAngle));
        }
    }


    //画标签
    private fun drawHorizontalTickLabels(
        chatLeft: Float, plotLeft: Float, canvas: Canvas,
        labelStartX: Float, labelStartY: Float,
        markeStopX: Float,
        text: String
    ) {
        val labelHeight = tickLabelPaint.lineHeight
        val textHeight = labelHeight / 4
        if (Paint.Align.LEFT == tickMarksAlign) //处理多行标签
        {
            var width = 0.0f
            width = if (isTickMarksVisible) {
                markeStopX - chatLeft
            } else {
                Math.sub(plotLeft, chatLeft)
            }
            drawLeftAxisTickMaskLabel(canvas, labelStartX, labelStartY + textHeight, text, width)
        } else {
            canvas.drawRotateText(
                getFormatterLabel(text), labelStartX, labelStartY + textHeight,
                tickLabelRotateAngle,  tickLabelPaint
            )
        }
    }


    //只针对renderHorizontalTick()，处理标签文字太长，分多行显示的情况,
    // 即只有在竖向图左轴，并且标签靠左显示时，才会处理这个问题
    private fun drawLeftAxisTickMaskLabel(
        canvas: Canvas,
        centerX: Float, centerY: Float, text: String, width: Float
    ) {
        if (!isAxisLabelsVisible) return

        //格式化后的标签文本.  
        val label: String = getFormatterLabel(text)

        //横向找宽度，竖向找高度，竖向的就不处理了。只搞横向多行的
        val txtLength =tickLabelPaint.textWidth(label)
        if (txtLength <= width) {
            //标签绘制在一行中
            canvas.drawRotateText(
                label, centerX, centerY,
                tickLabelRotateAngle,  tickLabelPaint
            )
        } else {    //Multi line			
            val txtHeight = tickLabelPaint.textHeight
            var charWidth = 0.0f
            var totalWidth = 0.0f
            var renderY = centerY
            var lnString = ""
            for (i in label.indices) {
                charWidth = tickLabelPaint.textWidth(label.substring(i, i + 1))
                
                totalWidth =  Math.add(totalWidth, charWidth)
                if (totalWidth.compareTo(width) == 1) {
                    canvas.drawRotateText(
                        lnString, centerX, renderY,
                        tickLabelRotateAngle,  tickLabelPaint
                    )
                    totalWidth = charWidth
                    renderY =  Math.add(renderY, txtHeight)
                    lnString = label.substring(i, i + 1)
                } else {
                    lnString += label.substring(i, i + 1)
                }
            } //end for
            if (lnString.isNotEmpty()) {
                canvas.drawRotateText(
                    lnString, centerX, renderY,
                    tickLabelRotateAngle,  tickLabelPaint
                )
            }
        } //end width if
    }


    abstract fun renderAxisLabels(
        canvas: Canvas,
        plotArea : Rectangle,
        lstLabels: MutableList<PlotAxisTick>,
        left:Float,
        moveX: Float,
        moveY: Float,
        axisLocation: ChartEnum.AxisLocation = this.axisLocation
    )


    /**
     * 检查Y轴的刻度是否显示
     * @param currentY    y坐标
     * @param moveY    y坐标平移值
     * @return    是否绘制
     */
    protected  fun isDrawYAxisTickMarks(plotArea : Rectangle, currentY: Float, moveY: Float): Boolean {
        return !(currentY.compareTo(plotArea.top - moveY) == -1 || currentY.compareTo(plotArea.bottom - moveY) == 1)
    }

    /**
     * 检查X轴的刻度是否显示
     * @param currentX    x坐标
     * @param moveX    x坐标平移值
     * @return 是否绘制
     */
    protected  fun isDrawXAxisTickMarks(plotArea : Rectangle, currentX: Float, moveX: Float): Boolean {
        if ((currentX + moveX).compareTo(plotArea.left) == -1) return false
        return (currentX + moveX).compareTo(plotArea.right) != 1
    }
}
